{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "9e2ba7e4",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import csv\n",
    "import matplotlib.pyplot as plt\n",
    "import os\n",
    "import json\n",
    "import openpyxl"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "88f632a0",
   "metadata": {},
   "source": [
    "### 第一问：（统计 Mashup中的包含Web API个数、Web API被使用的次数和Web API提供商发布Web API的个数）分析数据集中Mashup- API的历史调研记录，统计如下信息 1）每个Mashup包含的WebAPI个数 2）每个Web API被使用的次数 3）Web API提供商（URL网址）发布Web API的个数 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "00aa5f29",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Mashup: We-Wired Web                  37\n",
      "Mashup: DoAt (do@)                    29\n",
      "Mashup: Pixelpipe                     28\n",
      "Mashup: Sociotoco Search              24\n",
      "Mashup: Gawkk.com                     23\n",
      "                                      ..\n",
      "Mashup: iGlueHulu                      1\n",
      "Mashup: FlickrQ                        1\n",
      "Mashup: Infosniper IP on World Map     1\n",
      "Mashup: Notwifications                 1\n",
      "Mashup: Smarkets                       1\n",
      "Name: source, Length: 6071, dtype: int64\n",
      "/api/google-maps                             1984\n",
      "/api/twitter                                  671\n",
      "/api/youtube                                  562\n",
      "/api/flickr                                   474\n",
      "/api/facebook                                 381\n",
      "                                             ... \n",
      "/api/revel-systems                              1\n",
      "/api/lightspeed-retail                          1\n",
      "/api/microsoft-cognitive-services-emotion       1\n",
      "/api/tixik                                      1\n",
      "/api/topicalizer                                1\n",
      "Name: target, Length: 1508, dtype: int64\n",
      "提供商发布web api个数： 23579\n"
     ]
    }
   ],
   "source": [
    "# 获取Mashups调用API数据\n",
    "daTa = pd.read_csv(\"data/m-a_edges.csv\",sep=\"\\t\")\n",
    "print(daTa.source.value_counts())\n",
    "# 将数据写入csv文件\n",
    "daTa.source.value_counts().to_csv('result/api_dy.csv')\n",
    "\n",
    "print(daTa.target.value_counts())\n",
    "daTa.target.value_counts().to_csv('result/used_api.csv')\n",
    "    \n",
    "apis = set()#保存全部的api\n",
    "with open(\"./data/api_nodes_estimator.csv\",mode='r',encoding=\"utf-8\") as f:\n",
    "    reader = csv.reader(f)\n",
    "    for row in reader:\n",
    "        row=row[0].split(\"\\t\")\n",
    "        if(row[0]!=\"api\"):\n",
    "            continue\n",
    "        if(row[1][0]=='/'):\n",
    "            apis.add(row[1])\n",
    "print(\"提供商发布web api个数：\",len(apis))\n",
    "#  统计了总共的api个数,但没有各个URL对应的个数"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0adc7f61",
   "metadata": {},
   "source": [
    "### 每个Mashup包含的WebAPI个数 ，每个Web API被使用的次数  分别存储在result文件夹下"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "92b42748",
   "metadata": {},
   "source": [
    "## 对应url的api个数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "8b3035b5",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "twitter.com              11247\n",
      "github.com                 939\n",
      "groups.google.com          350\n",
      "programmableweb.com        292\n",
      "stackoverflow.com          220\n",
      "                         ...  \n",
      "wallarm.com                  1\n",
      "api.wallarm.com              1\n",
      "knoema.com                   1\n",
      "api.lolwallpapers.net        1\n",
      "api.lymbix.com               1\n",
      "Name: API_pr, Length: 25871, dtype: int64\n"
     ]
    }
   ],
   "source": [
    "API=set()\n",
    "url_data=[]\n",
    "\n",
    "#  存储全部文件路径\n",
    "file_name = ['data/raw/accessibility/api_accessibility/api_version_accessbiliby-1.txt','data/raw/accessibility/api_accessibility/api_version_accessbiliby-2.txt','data/raw/accessibility/api_accessibility/api_version_accessbiliby-3.txt','data/raw/accessibility/api_accessibility/api_version_accessbiliby-4.txt','data/raw/accessibility/api_accessibility/api_version_accessbiliby-5.txt']\n",
    "for fil in file_name:\n",
    "    with open(fil,'r') as file:\n",
    "        urlFile = file.read()\n",
    "    urlContent = json.loads(urlFile)\n",
    "    for msg in urlContent:\n",
    "        API_title = msg['from_api']['api_title']\n",
    "        if API_title in API:\n",
    "            continue\n",
    "        else:\n",
    "\n",
    "            API.add(API_title)\n",
    "            API_pr = \"\"\n",
    "            API_prs = set()\n",
    "            for visit in msg['visit_status']:\n",
    "                server_tmp = visit['visit_url'].split('/')[2].split('.')\n",
    "                if server_tmp[0] == \"www\":\n",
    "                    API_pr='.'.join(server_tmp[1:])\n",
    "                else:\n",
    "                    API_pr='.'.join(server_tmp)\n",
    "                API_prs.add(API_pr)\n",
    "            for API_pr in API_prs:\n",
    "                url_data.append([API_pr,API_title])\n",
    "colu=['API_pr','API']\n",
    "df=pd.DataFrame(data=url_data,columns=colu)\n",
    "df.to_csv(\"result/api_url.csv\",sep=\"\\t\")\n",
    "\n",
    "urls = pd.read_csv('result/api_url.csv',sep=\"\\t\")\n",
    "urls.API_pr.value_counts().to_csv(\"result/api_url.csv\")\n",
    "# 输出所有服务提供商提供接口数目的数据\n",
    "print(urls.API_pr.value_counts())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "41116e25",
   "metadata": {},
   "source": [
    "### 对应url的api个数存储在result/api_url.csv中，可见大多数网址只提供一个api接口，也有很多提供上百个的\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cde77bee",
   "metadata": {},
   "source": [
    "# 第二问：从需求关键词视角，分析在不同标注Tag或者Category类别中， 编程开发人员的组合需求（Mashup）与该需求所调用的服务（Web API）的关联情况。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "f996480d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "            category  used count  times of invoke similar APIs  \\\n",
      "0           Payments          22                            16   \n",
      "1             Photos         656                           486   \n",
      "2    Recommendations          49                             9   \n",
      "3            Loyalty           1                             0   \n",
      "4           Scanning           4                             0   \n",
      "..               ...         ...                           ...   \n",
      "409            Gifts           8                             0   \n",
      "410           Babies           3                             0   \n",
      "411          Webcams          14                             2   \n",
      "412   Authentication           4                             2   \n",
      "413          Italian          21                             0   \n",
      "\n",
      "    Proportion of invoking similar APIs  \n",
      "0                                72.73%  \n",
      "1                                74.09%  \n",
      "2                                18.37%  \n",
      "3                                 0.00%  \n",
      "4                                 0.00%  \n",
      "..                                  ...  \n",
      "409                               0.00%  \n",
      "410                               0.00%  \n",
      "411                              14.29%  \n",
      "412                              50.00%  \n",
      "413                               0.00%  \n",
      "\n",
      "[414 rows x 4 columns]\n"
     ]
    }
   ],
   "source": [
    "# 生成二维列表，用于记录category中调用API种类\n",
    "categories = []\n",
    "with open(\"data/raw/api_mashup/active_mashups_data.txt\",\"r\") as file:\n",
    "    data=file.read()\n",
    "content=json.loads(data)\n",
    "for msg in content:\n",
    "    categories+=msg['categories']\n",
    "categories_tmp = list(set(categories))\n",
    "categories=[]\n",
    "for category in categories_tmp:\n",
    "    item=[category,0,0]\n",
    "    categories.append(item)\n",
    "for i in range(len(categories)):\n",
    "    for msg in content:\n",
    "        if categories[i][0] in msg['categories']:\n",
    "            categories[i][1]+=1\n",
    "            for api in msg['related_apis']:\n",
    "                if api!=None:\n",
    "                    if categories[i][0] in api['tags']:\n",
    "                        categories[i][2]+=1\n",
    "                        break\n",
    "cols=['category','used count','times of invoke similar APIs']\n",
    "df=pd.DataFrame(data=categories,columns=cols)\n",
    "propotions=[]\n",
    "for item in categories:\n",
    "    propotion=\"%.2f%%\"%(item[2]/item[1]*100)\n",
    "    propotions.append(propotion)\n",
    "# print(propotions)\n",
    "df['Proportion of invoking similar APIs']=propotions\n",
    "print(df)\n",
    "df.to_csv(\"result/categories.csv\",sep=\"\\t\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "96f32855",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<AxesSubplot:>"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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W50uq0rnzp3zW2/fvr1ZvXq1b3327NmmefPmdVzV97du3TqTnJxsGjdubBo0aGAaN25sVq5c6XRZAQvGfjCm7BaM/XDDmAqGPnAOiqQOHTro9ddf962HhYXp6NGjvvUjR44oIiLCidK+l9/85jf63e9+p6KiIh0/flwDBw7UXXfd5XRZVfrJT36i7du3+9ZLS0vVrFkz33qzZs305ZdfOlFaQMx35j8cMWKEFi5cqKNHj+qLL77Qn/70J917770OVVd9bugHY8oubuiHG8ZUUPTB0XhkiZycHJORkWFuuukmc+jQIV+iT0xMNAkJCaZx48Zm+fLlTpd5XgMGDDCfffaZb/3yyy83x48f961v3rzZJCQkOFFatW3evNm0a9fOjBgxwhQVFZlXX33VxMfHm86dO5v27dub6OhoM2fOHKfLPK+OHTuabdu2+dbT09PNRx995FtfuXKlSUpKcqK0gLihH4wpu7ihH24YU8HQBwLKtyxcuND88Ic/NDNmzDCnT58277//vtmxY4c5c+aM06VVy+LFi02LFi3M9OnTzblz58yMGTNMUlKSGTRokBk4cKCJj483f/zjH50u87zKysrMU089ZS6//HLz+uuvmyNHjphly5aZJUuWmEOHDjldXrUEww9/dbilH4wpe7ilH24YU7b3gXvxfMeJEyc0atQo7d69W88//7zatm3rdEkBOXnypP7whz9ox44dmj17tsLCwrRmzRqdPXtW3bp1U6dOnZwusdoOHDige++9V7GxsZoxY4aSk5OdLikgX331lZ5++mktWLBATz/9tK666irflWE/+clPgqY/bumHxJiyhVv6IQX/mJIs7oPTCckWK1asMH/+859NZmamMcaY1atXm9atW5tRo0aZ06dPO1xd4NavX2/atGljRo4caYqLi50uJyB79uwx//jHP3wnKs+bN89ceuml5rnnnnO4sguTnZ1trrnmGjNw4EAr/iq5UMHcD8aUnYK5H24YU7b3gYBijPn9739vmjRpYgYNGmQuvfRS8+STTxpjjCkpKTFjx441LVu2NCtWrHC4yur54osvzNatW83JkydNaWmpGTdunGnZsqV54403nC6tWqZOnWqioqJM586dTcOGDc3zzz9vjDHm888/N3feeae56qqrzPvvv+9wldVj+w9/dQV7PxhT9gn2frhhTAVDHwgoxpiEhATf5bfHjx83LVq08GvfvXu36datmxOlBWTRokUmKirKJCYmmri4OPP6668bY4zZu3evufrqq82tt95q8vPzHa6yaklJSeadd94xxhhz8OBB06pVK7/2VatWldtmo2D44a8ON/SDMWUXN/TDDWMqGPpAQDHGpKSkmFdffdUYY0xWVpZp06aNwxVdmNTUVPPyyy8bY4zZunWr+dGPfuTXPnv2bJOWluZEadWWmJho1qxZY4wxJjc311x++eXl9gmGk5aD4Ye/OtzQD8aUXdzQDzeMqWDoAzPJSpo4caLuuusuPfjggzp9+rTmz5/vdEkX5NSpU7r88sslSZdddplOnz7t1/7rX/9aN910kwOVVd+oUaN0/fXXq23btvrwww81YcKEcvvUq1fPgcoCY4xRSMjX0wyFhoaWm/uhT58+2rFjhxOlBcQN/WBM2cUN/XDDmAqKPjiXjexy7Ngx895775kTJ044XcoFe/jhh43X6zW33367adGihRk/frzTJV2QXbt2mVdeecXs3bvX6VIu2JQpU0x0dLTp0qWLSUhIMLNnz3a6pAviln4wpuzhln64YUzZ3gcuM3aZf/3rX9q3b5/atm2rvn37Ol3ORW337t3au3ev2rRpo1atWjldzgVzSz/cwC3vhVv6gdpFQPk/W7Zs0bRp07Rx40bl5+fL4/EoMTFRXbt21cMPP6yOHTs6XeJF47PPPtOsWbMqfC9++9vfKiUlxekSEWQYU6hpbhhTtveBgCJp6dKluu2229S7d29de+21SkxMlDFGR48e1apVq/T222/rlVde0Y033uh0qedVXFysl156qdyA69atm26//XbVr1/f6RKrtGHDBmVkZCglJUV9+/b1ey8yMzOVm5urlStXqlu3bk6Xel579+7V5s2b1aVLF7Vq1Ur79u3T9OnTVVJSojvvvFO9evVyusRqsf2X2Pm4aUwF+3tRHbm5uRo3bpzmzp3rdCmVcsOYCoY+EFAkpaen684779Sjjz5aYfvkyZO1YMEC7dmzp44rC8wHH3ygPn366PTp0+revbvfgFu7dq3q16+vVatWqXXr1k6XWqlOnTrppz/9qaZOnVph+8MPP6wNGzZoy5YtdVxZYP7973/rxhtv1CWXXKLTp09ryZIluuuuu9S2bVsZY7R27Vq9+eab1oeUYPgldj5uGVNueC+qY+fOnWrfvr3Onj3rdCmVcsOYCoY+EFD09ZnK77//vlq2bFlh+/79+9W2bVvn7+x4Hj179lRSUpLmz59f7u7LpaWlGjp0qPLy8rR69WqHKjy/qKgoZWVl+a5G+q59+/apXbt2OnPmTB1XFpiuXbuqV69e+tOf/qRFixbpvvvu07333qunnnpKkjR27Fht2bJFq1atcrjSqgXDL7HzccuYcsN7IUnLli2rsv3jjz/WI488YnVAccOYCoo+1PFJuVZq3bq1mTx5cqXtkydPNldccUUdVnRhoqKizJ49eypt37Vrl4mKiqrDigKXlpZm5s6dW2n73LlzrZ/LxRhjYmNjTXZ2tjHGmLNnz5qwsDC/O7ju2rXLJCYmOlVetdWrV8/s27ev0va9e/eaevXq1WFFgXPLmHLDe2GMMR6Px4SEhBiPx1PpEhIS4nSZVXLDmAqGPjAPiqQnn3xSgwcP1tq1a32HTj0ej/Lz85WZmalVq1Zp0aJFTpd5Xg0aNFB2dnalX+EcOHBADRo0qOOqAjNq1Cj99re/1bZt29SnT59y78Xf/vY3TZs2zekyAxISEqJ69eopPj7ety0mJkYFBQXOFVVNXq9XGzdurPSvrE2bNsnr9dZxVYFxy5hyw3shfd2P5557rtI5mbKystShQ4e6LSpAbhhTQdEHR+ORRTZu3GgGDRpkmjVrZiIiIkxERIRp1qyZGTRokNm4caPT5VXLuHHjTFxcnJkyZYrJysoyeXl5Jj8/32RlZZkpU6aYBg0aBMXcKIsWLTKdO3c2YWFhvr+owsLCTOfOnc3ixYudLq9afvSjH5mVK1f61nft2mXKysp86+vXr3f8r5PqeO6550xERIS5//77zdKlS82mTZvM5s2bzdKlS839999vIiMjzaxZs5wu87zcMKbc8l7079/fPP7445W2Z2VlGY/HU4cVXRg3jCnb+0BAcZlJkyYZr9frO0z6zaFUr9db5ddYNiotLTWHDx82hw8fNqWlpU6XE5BZs2ZVeYPGxx57zAwbNqwOK7pwtv8SC0Qwjylj3PFerFu3zi+8f1dRUZFvCvZgEOxjyhh7+8BJst9x9uxZHTt2TB6PRwkJCQoNDXW6pAuSk5Oj/Px8SVJSUpLS0tIcrgjBrqysTMeOHZMkNWrUSOHh4Q5XdPHivcDFIMTpAmyxZMkSdevWTdHR0UpOTpbX61V0dLS6deumpUuXOl1ewNLS0tSlSxd16dIl6MLJli1bdMcddygtLU1RUVGKjo5WWlqa7rjjDm3dutXp8i5a4eHh8nq98nq9QfeB6LYxFczvhVu4YUzZ3geOoEiaPXu2HnzwQd19993lJmp78803NW/ePM2YMUPDhw93utTzCvaJnNw0aV5mZqY2bNig7t27q1evXlq3bp0mTpyokpIS/fKXv9SvfvUrp0uslmCfZdktY6q0tNRv+oCPPvpIM2bMUHZ2trxer+69917rTy6tjo8++kjDhw/XO++843QplXLDmAqKPjj25ZJFLrvsMvO3v/2t0vY5c+aYSy+9tA4rujDr1683l1xyibniiivMQw89ZCZMmGCeeuop89BDD5nWrVubmJgYs2HDBqfLrNKVV15pJk6cWGn7pEmTTOvWreuwogvz97//3YSFhZn27dubSy65xMybN8/Ex8ebe+65xwwbNsxERESYV1991ekyz2vJkiUmPDzcXHfddWbq1KnmpZdeMgsXLjRTp041GRkZJiIiwixdutTpMqvkljEVEhJijhw5YowxZseOHSY6Otr8+Mc/NsOHDzedOnUyERER5t1333W4yu8vKyvL+suM3TCmgqEPHEFRkExYUw1umMjJLZPmtWvXTr/61a/04IMP6u2331b//v311FNP6eGHH5YkPfvss/rnP/+pDRs2OFxp1dwwy7JbxlRISIjy8/PVpEkT9e/fX/Xq1dMrr7wij8cjSbr77ruVl5enlStXOlxp1f7nf/6nyvZDhw7pz3/+s9UTtblhTAVFHxyNR5bo0KGDGTlyZKXtI0eONB06dKjDii6MGyZycsukefXr1zcff/yxbz08PNzs3LnTt75v3z6TkJDgRGkBiYyMNPv376+0fd++fSYyMrIOKwqcW8aUx+PxHUFp2rRpuaOhWVlZQTH5n8fjMcnJyaZ58+YVLsnJydYfQXHDmAqGPjBRm6RnnnlG/fr107///e8KJ2r75JNPtGLFCqfLPC83TOTklknzwsPDVVpa6luPjIzUJZdc4luPiIiw/oicJF122WVaunSpRo8eXWH766+/rksvvbSOqwqMW8aUx+PxHS0JDQ1VbGysX3tsbGxQTP6XmpqqyZMn67bbbquwPRgmanPDmAqKPjgajyySk5NjRo8eba6++mrTsmVL07JlS3P11VebP/zhDyYnJ8fp8qrFLRM5uWHSvI4dO/qdm1FQUGDOnTvnW8/MzDQtW7Z0orSA/OMf/zBhYWHm+uuvN9OmTTMvv/yyWbRokZk2bZrp16+fCQ8PN6+99prTZZ6XG8aUx+Mx8fHxpkGDBiY8PNwsXLjQr/3NN980zZs3d6i66rvlllvM6NGjK20Plona3DCmbO8D56C4zOLFizV16lRt27bN9x1uaGioOnTooJEjR1b6Vwtq1pIlS5SQkKCrr766wvZJkyapuLhYf/zjH+u4ssBt2rRJ06dP16ZNm/zm1unSpYseeughdenSxeEKLw7z58/3W2/VqpU6d+7sW3/yySd18uRJPfvss3VdWkA++OADnT59utKrv8rKynT48GGlpqbWcWWwDQHFpZjICQAQzJiorRqGDBmiXr16OV1GQNw6kdNjjz2mu+++2+ky4CKMKdQ0N4wpG/pAQKmG5ORkVxxu/Mtf/qInn3zS6TK+l0OHDungwYNOl/G92fDDXxPc0A/GlF3c0A83jCkb+sBXPBeR3r17KycnRx9//LHTpVz0hgwZotzcXKtny6wOt/TDDdzyXrilH/j+CCj/p6op4u+99141bdrU6RIBALhoEFAkbdiwQRkZGUpJSfFdD27+754EmZmZys3N1cqVK9WtWzenS73olJWVafny5b77jdx8882qX7++02UhyBQXF+ull14q9wdIt27ddPvttzOmEDA3jCnb+0BAkTumiP+GMUZvvfVWhQOud+/evomebNW1a1etWLFC8fHx+vzzz9W7d2/t379fqampys3NVZMmTbRx40b94Ac/cLrU8zp+/Ljef/99tW3bVg0bNtSxY8c0Z84clZSU6NZbb9UVV1zhdInVYvsvsfP54IMP1KdPH50+fVrdu3f3+wNk7dq1ql+/vlatWqXWrVs7XWqVnnnmGf385z93xflwVTly5Ihmz56t//7v/3a6lEq5YUwFQx8IKHLPvXgOHTqkG264Qbt27VJ6errfgNu9e7fatm2rZcuWWf3h/u37jfz617/Wli1btHLlSiUlJen48eMaMGCAWrVqpTlz5jhdapXee+899e3bV4WFhYqPj1dmZqZuvfVWhYWFyRijQ4cOacOGDWrfvr3TpVYpGH6JnU/Pnj2VlJSk+fPn+90NWPr6DsFDhw5VXl6eVq9e7VCF1RMSEqKQkBD17NlT99xzj26++eZy/XGDnTt3qn379lbfi8cN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\n",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "df['Proportion of invoking similar APIs'].value_counts()\n",
    "df['Proportion of invoking similar APIs'].value_counts()[:10].plot(kind='bar')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f12a6c0c",
   "metadata": {},
   "source": [
    "# 图中记录了调⽤相应类别API的⽐例频率比例。\n",
    "## 其中调用同类Web API概率为0.00%的占⽐约为67%，\n",
    "## 而调⽤同类Web API概率为100.00%的占⽐约为6%，表现出较弱的关联性。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ed9b5b14",
   "metadata": {},
   "source": [
    "# 第三问：\n",
    "## 从非功能视角（例如API之间的兼容性，Web API不同的服务接口协议REST、RPC），对功能类别相等的若干 Web API进行分析（ Web API Tag 标注值 或者 Web API 所属 Category 类别相等）。在Tag 取值相等 或者 Category取值相等的Web API集合内，统计API被使用的情况，尝试从非功能视角进行原因分析（例如API之间的兼容性，Web API不同的服务接口协议REST、RPC） 注：API之间的兼容性是指 历史上共同被调用的情况。如果有过共同调用的记录，说明这两个API兼容"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "7560b2f1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Localization\n",
      "{'RPC': 13, 'REST': 175, 'Indirect': 3, 'Unspecified': 10, 'Native/Browser': 1, 'FEED': 4}\n",
      "Search\n",
      "{'REST': 899, 'RPC': 92, 'FEED': 33, 'Indirect': 9, 'Streaming': 4, 'Native/Browser': 7, 'Unspecified': 24}\n"
     ]
    }
   ],
   "source": [
    "datas=[]\n",
    "tags={}\n",
    "pathes=[\"./data/raw/api_mashup/active_apis_data.txt\",\"./data/raw/api_mashup/deadpool_apis_data.txt\"]\n",
    "for path in pathes:\n",
    "    f = open(path, encoding=\"utf-8\")\n",
    "    datas += json.load(f)\n",
    "\n",
    "for i,data in enumerate(datas):\n",
    "    if data==None:\n",
    "        continue\n",
    "\n",
    "    alltag=data[\"tags\"]\n",
    "    if len(data['versions'])==0:\n",
    "        continue\n",
    "    style=data['versions'][0]['style']\n",
    "    for tag in alltag:\n",
    "        if tag not in tags:\n",
    "            tags[tag]={}\n",
    "        tags[tag][style]=tags[tag].get(style,0)+1\n",
    "print('Localization')\n",
    "print(tags['Localization'])\n",
    "print('Search')\n",
    "print(tags['Search'])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "73702de3",
   "metadata": {},
   "source": [
    "### 版本协议角度进行数据处理"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "111175ac",
   "metadata": {},
   "source": [
    "基于不同协议的api调用表现出明显的差异性"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "88bd832d",
   "metadata": {},
   "source": [
    "一般而言，接口适配的协议数量越多，代表着接口匹配的使用场景越多。\n",
    "因此，这样的接口使用频率也会越高。\n",
    "同时根据类别和需求的变更，协议也会影响调用次数。如REST协议更为规范标准，作为通用协议而得到更广泛的应用如：对外服务、低频服务等等；\n",
    "⽽RPC协议的性能更⾼，若是追求高性能且可以忽视其⾼耦合性带来的缺陷，此时则更应该选择RPC协议。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "99e8690e",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
